#include "SpikeRecoveryTestDemo.h"

#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QMessageBox>

SpikeRecoveryTestDemo::SpikeRecoveryTestDemo(QWidget* parent)
    : QWidget(parent),
      m_modbusHelper(nullptr),
      m_connected(false),
      m_currentStep(0),
      m_testRunning(false),
      m_stepTimer(new QTimer(this)),
      m_pollTimer(new QTimer(this)),
      m_concentration1(10.5f),
      m_concentration2(15.8f),
      m_recoveryRate(0.0f),
      m_stepDelay(2000)  // 默认2秒延迟
{
    setupUI();

    // 初始化Modbus助手
    m_modbusHelper = new ModbusHelper(this);
    connect(m_modbusHelper, &ModbusHelper::errorOccurred, this,
            &SpikeRecoveryTestDemo::onModbusError);
    connect(m_modbusHelper, &ModbusHelper::commSuccess, this,
            &SpikeRecoveryTestDemo::onModbusSuccess);

    // 定时器设置
    m_stepTimer->setSingleShot(true);
    m_stepTimer->setInterval(STEP_TIMEOUT);
    connect(m_stepTimer, &QTimer::timeout, this, [this]() { onStepFailed("步骤执行超时"); });

    m_pollTimer->setInterval(POLL_INTERVAL);
    connect(m_pollTimer, &QTimer::timeout, this, &SpikeRecoveryTestDemo::pollReadyStatus);

    updateUI();
    logMessage("加标回收测试Demo已启动");
}

SpikeRecoveryTestDemo::~SpikeRecoveryTestDemo()
{
    if (m_modbusHelper && m_connected) {
        // ModbusHelper会自动处理断开连接
    }
}

void SpikeRecoveryTestDemo::setupUI()
{
    setWindowTitle("加标回收测试Demo");
    resize(800, 600);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);

    // 连接组
    m_connectionGroup = new QGroupBox("Modbus连接", this);
    QHBoxLayout* connLayout = new QHBoxLayout(m_connectionGroup);

    connLayout->addWidget(new QLabel("串口:"));
    m_portSpinBox = new QSpinBox();
    m_portSpinBox->setRange(1, 10);
    m_portSpinBox->setValue(4);
    connLayout->addWidget(m_portSpinBox);

    m_connectBtn = new QPushButton("连接");
    m_disconnectBtn = new QPushButton("断开");
    m_connectionStatus = new QLabel("未连接");

    connLayout->addWidget(m_connectBtn);
    connLayout->addWidget(m_disconnectBtn);
    connLayout->addWidget(m_connectionStatus);
    connLayout->addStretch();

    connect(m_connectBtn, &QPushButton::clicked, this, &SpikeRecoveryTestDemo::onConnectClicked);
    connect(m_disconnectBtn, &QPushButton::clicked, this,
            &SpikeRecoveryTestDemo::onDisconnectClicked);

    // 测试控制组
    m_testControlGroup = new QGroupBox("测试控制", this);
    QVBoxLayout* testLayout = new QVBoxLayout(m_testControlGroup);

    QHBoxLayout* btnLayout = new QHBoxLayout();
    m_startTestBtn = new QPushButton("开始测试");
    m_stopTestBtn = new QPushButton("停止测试");
    m_resetBtn = new QPushButton("重置");

    btnLayout->addWidget(m_startTestBtn);
    btnLayout->addWidget(m_stopTestBtn);
    btnLayout->addWidget(m_resetBtn);
    btnLayout->addStretch();

    connect(m_startTestBtn, &QPushButton::clicked, this,
            &SpikeRecoveryTestDemo::onStartTestClicked);
    connect(m_stopTestBtn, &QPushButton::clicked, this, &SpikeRecoveryTestDemo::onStopTestClicked);
    connect(m_resetBtn, &QPushButton::clicked, this, &SpikeRecoveryTestDemo::onResetClicked);

    m_progressBar = new QProgressBar();
    m_progressBar->setRange(0, TOTAL_STEPS);
    m_progressBar->setValue(0);

    m_currentStepLabel = new QLabel("当前步骤: 等待开始");

    testLayout->addLayout(btnLayout);
    testLayout->addWidget(m_progressBar);
    testLayout->addWidget(m_currentStepLabel);

    // 步骤状态显示
    QHBoxLayout* stepsLayout = new QHBoxLayout();
    for (int i = 0; i < TOTAL_STEPS; ++i) {
        QLabel* stepLabel = new QLabel(QString("步骤%1").arg(i + 1));
        stepLabel->setStyleSheet("QLabel { border: 1px solid gray; padding: 5px; margin: 2px; }");
        stepLabel->setMinimumWidth(60);
        stepLabel->setAlignment(Qt::AlignCenter);
        m_stepLabels.append(stepLabel);
        stepsLayout->addWidget(stepLabel);
    }
    testLayout->addLayout(stepsLayout);

    // 测试数据组
    m_testDataGroup = new QGroupBox("测试数据", this);
    QHBoxLayout* dataLayout = new QHBoxLayout(m_testDataGroup);

    dataLayout->addWidget(new QLabel("第一次浓度:"));
    m_concentration1SpinBox = new QDoubleSpinBox();
    m_concentration1SpinBox->setRange(0.0, 1000.0);
    m_concentration1SpinBox->setDecimals(2);
    m_concentration1SpinBox->setValue(m_concentration1);
    dataLayout->addWidget(m_concentration1SpinBox);

    dataLayout->addWidget(new QLabel("第二次浓度:"));
    m_concentration2SpinBox = new QDoubleSpinBox();
    m_concentration2SpinBox->setRange(0.0, 1000.0);
    m_concentration2SpinBox->setDecimals(2);
    m_concentration2SpinBox->setValue(m_concentration2);
    dataLayout->addWidget(m_concentration2SpinBox);

    dataLayout->addWidget(new QLabel("加标回收率:"));
    m_recoveryRateLabel = new QLabel("0.00%");
    m_recoveryRateLabel->setStyleSheet("QLabel { font-weight: bold; color: blue; }");
    dataLayout->addWidget(m_recoveryRateLabel);

    // 添加步骤延迟控制
    dataLayout->addWidget(new QLabel("步骤延迟(秒):"));
    m_stepDelaySpinBox = new QSpinBox();
    m_stepDelaySpinBox->setRange(0, 60);               // 0-60秒
    m_stepDelaySpinBox->setValue(m_stepDelay / 1000);  // 转换为秒
    m_stepDelaySpinBox->setSuffix("s");
    dataLayout->addWidget(m_stepDelaySpinBox);

    // 连接信号，当用户修改延迟时间时更新内部变量
    connect(m_stepDelaySpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
            [this](int value) {
                m_stepDelay = value * 1000;  // 转换为毫秒
                logMessage(QString("步骤延迟已设置为 %1 秒").arg(value));
            });

    dataLayout->addStretch();

    // 日志组
    m_logGroup = new QGroupBox("运行日志", this);
    QVBoxLayout* logLayout = new QVBoxLayout(m_logGroup);

    m_logTextEdit = new QTextEdit();
    m_logTextEdit->setMaximumHeight(150);
    logLayout->addWidget(m_logTextEdit);

    // 添加到主布局
    mainLayout->addWidget(m_connectionGroup);
    mainLayout->addWidget(m_testControlGroup);
    mainLayout->addWidget(m_testDataGroup);
    mainLayout->addWidget(m_logGroup);
}

void SpikeRecoveryTestDemo::updateUI()
{
    m_connectBtn->setEnabled(!m_connected);
    m_disconnectBtn->setEnabled(m_connected);
    m_startTestBtn->setEnabled(m_connected && !m_testRunning);
    m_stopTestBtn->setEnabled(m_testRunning);
    m_resetBtn->setEnabled(!m_testRunning);

    m_connectionStatus->setText(m_connected ? "已连接" : "未连接");
    m_connectionStatus->setStyleSheet(m_connected ? "color: green;" : "color: red;");
}

void SpikeRecoveryTestDemo::onConnectClicked()
{
    QString portName = QString("COM%1").arg(m_portSpinBox->value());
    logMessage(QString("尝试连接到 %1...").arg(portName));

    // 使用RTU模式连接，波特率38400，从站地址1
    if (m_modbusHelper->createModbus_rtu(portName, 9600, 1)) {
        m_connected = true;
        logMessage("Modbus连接成功");
    } else {
        m_connected = false;
        logMessage(QString("Modbus连接失败: %1").arg(m_modbusHelper->getLastError()));
        QMessageBox::warning(this, "连接失败", m_modbusHelper->getLastError());
    }

    updateUI();
}

void SpikeRecoveryTestDemo::onDisconnectClicked()
{
    if (m_testRunning) {
        stopTestSequence();
    }

    m_connected = false;
    logMessage("Modbus连接已断开");
    updateUI();
}

void SpikeRecoveryTestDemo::onStartTestClicked()
{
    if (!m_connected) {
        QMessageBox::warning(this, "警告", "请先连接Modbus设备");
        return;
    }

    // 获取用户输入的浓度值
    m_concentration1 = m_concentration1SpinBox->value();
    m_concentration2 = m_concentration2SpinBox->value();

    startTestSequence();
}

void SpikeRecoveryTestDemo::onStopTestClicked() { stopTestSequence(); }

void SpikeRecoveryTestDemo::onResetClicked() { resetTestSequence(); }

void SpikeRecoveryTestDemo::startTestSequence()
{
    logMessage("=== 开始加标回收测试序列 ===");
    m_testRunning = true;
    m_currentStep = 0;
    m_recoveryRate = 0.0f;
    m_recoveryRateLabel->setText("0.00%");

    // 重置所有步骤状态
    for (auto& label : m_stepLabels) {
        label->setStyleSheet("QLabel { border: 1px solid gray; padding: 5px; margin: 2px; }");
    }

    updateUI();
    executeNextStep();
}

void SpikeRecoveryTestDemo::stopTestSequence()
{
    logMessage("=== 测试序列已停止 ===");
    m_testRunning = false;
    m_stepTimer->stop();
    m_pollTimer->stop();
    updateUI();
}

void SpikeRecoveryTestDemo::resetTestSequence()
{
    m_currentStep = 0;
    m_recoveryRate = 0.0f;
    m_recoveryRateLabel->setText("0.00%");
    m_progressBar->setValue(0);
    m_currentStepLabel->setText("当前步骤: 等待开始");

    // 重置所有步骤状态
    for (auto& label : m_stepLabels) {
        label->setStyleSheet("QLabel { border: 1px solid gray; padding: 5px; margin: 2px; }");
    }

    logMessage("测试序列已重置");
}

void SpikeRecoveryTestDemo::executeNextStep()
{
    if (!m_testRunning || m_currentStep >= TOTAL_STEPS) {
        return;
    }

    m_currentStep++;
    m_progressBar->setValue(m_currentStep);

    QString stepName = QString("步骤%1").arg(m_currentStep);
    m_currentStepLabel->setText(QString("当前步骤: %1").arg(stepName));

    // 设置当前步骤为进行中状态
    setStepStatus(m_currentStep - 1, "running");

    // 启动超时定时器
    m_stepTimer->start();

    executeStep(m_currentStep);
}

void SpikeRecoveryTestDemo::executeStep(int stepIndex)
{
    switch (stepIndex) {
        case 1:
            step1_SetSpikeRecovery();
            break;
        case 2:
            step2_SetDynamicSpike();
            break;
        case 3:
            step3_StartProcess();
            break;
        case 4:
            step4_WaitReady1();
            break;
        case 5:
            step5_StartAnalysis1();
            break;
        case 6:
            step6_WriteConcentrationAndFinish1();
            break;
        case 7:
            step7_WaitReady2();
            break;
        case 8:
            step8_StartAnalysis2();
            break;
        case 9:
            step9_WriteConcentrationAndFinish2();
            break;
        case 10:
            step10_ReadRecoveryRate();
            break;
        case 11:
            step11_TestComplete();
            break;
        default:
            onStepFailed("未知步骤");
            break;
    }
}

void SpikeRecoveryTestDemo::onStepCompleted()
{
    m_stepTimer->stop();

    // 设置当前步骤为完成状态
    setStepStatus(m_currentStep - 1, "completed");

    if (m_currentStep >= TOTAL_STEPS) {
        // 所有步骤完成
        m_testRunning = false;
        logMessage("=== 加标回收测试完成 ===");
        updateUI();
    } else {
        // 继续下一步，使用配置的延迟时间
        QTimer::singleShot(m_stepDelay, this, &SpikeRecoveryTestDemo::executeNextStep);
    }
}

void SpikeRecoveryTestDemo::onStepFailed(const QString& error)
{
    m_stepTimer->stop();
    m_pollTimer->stop();

    // 设置当前步骤为失败状态
    setStepStatus(m_currentStep - 1, "failed");

    logMessage(QString("步骤%1失败: %2").arg(m_currentStep).arg(error));

    m_testRunning = false;
    updateUI();

    QMessageBox::critical(this, "测试失败",
                          QString("步骤%1执行失败:\n%2").arg(m_currentStep).arg(error));
}

void SpikeRecoveryTestDemo::onModbusError(const QString& error)
{
    logMessage(QString("Modbus错误: %1").arg(error));
}

void SpikeRecoveryTestDemo::onModbusSuccess()
{
    // Modbus操作成功，可以在这里记录日志
}

// 具体测试步骤实现
void SpikeRecoveryTestDemo::step1_SetSpikeRecovery()
{
    logMessage("步骤1: 设置加标回收模式 (006FH = 0x0001)");

    QVector<quint16> values = {0x0001};
    m_modbusHelper->asyncWrite(REG_SPIKE_MODE, values)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step2_SetDynamicSpike()
{
    logMessage("步骤2: 设置动态加标 (0064H = 0x01)");

    QVector<quint16> values = {0x0001};
    m_modbusHelper->asyncWrite(REG_DYNAMIC_SPIKE, values)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step3_StartProcess()
{
    logMessage("步骤3: 启动流程 (0099H = 0x01)");

    QVector<quint16> values = {0x0001};
    m_modbusHelper->asyncWrite(REG_START_PROCESS, values)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step4_WaitReady1()
{
    logMessage("步骤4: 等待第一次准备完成 (读取0303H)");
    m_pollTimer->start();
}

void SpikeRecoveryTestDemo::step5_StartAnalysis1()
{
    logMessage("步骤5: 开始第一次分析 (0302H = 0x0001)");

    QVector<quint16> values = {0x0001};
    m_modbusHelper->asyncWrite(REG_ANALYSIS_CONTROL, values)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step6_WriteConcentrationAndFinish1()
{
    logMessage(QString("步骤6: 写入第一次浓度值 %1 并完成分析 (0300H-0302H)")
                   .arg(m_concentration1, 0, 'f', 2));

    // 将浓度值转换为2个寄存器 + 分析完成标志
    QVector<float> floatValues = {m_concentration1};
    QVector<quint16> floatRegs = m_modbusHelper->floatsToRegisters(floatValues, MB_ABCD);

    // 添加分析完成标志 (0x0000)
    QVector<quint16> allValues = floatRegs;
    allValues.append(0x0000);

    // 一次性写入3个连续寄存器: 浓度值(2个) + 分析完成标志(1个)
    m_modbusHelper->asyncWrite(REG_CONCENTRATION_LOW, allValues)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step7_WaitReady2()
{
    logMessage("步骤7: 等待第二次准备完成 (读取0303H)");
    m_pollTimer->start();
}

void SpikeRecoveryTestDemo::step8_StartAnalysis2()
{
    logMessage("步骤8: 开始第二次分析 (0302H = 0x0001)");

    QVector<quint16> values = {0x0001};
    m_modbusHelper->asyncWrite(REG_ANALYSIS_CONTROL, values)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step9_WriteConcentrationAndFinish2()
{
    logMessage(QString("步骤9: 写入第二次浓度值 %1 并完成分析 (0300H-0302H)")
                   .arg(m_concentration2, 0, 'f', 2));

    // 将浓度值转换为2个寄存器 + 分析完成标志
    QVector<float> floatValues = {m_concentration2};
    QVector<quint16> floatRegs = m_modbusHelper->floatsToRegisters(floatValues, MB_ABCD);

    // 添加分析完成标志 (0x0000)
    QVector<quint16> allValues = floatRegs;
    allValues.append(0x0000);

    // 一次性写入3个连续寄存器: 浓度值(2个) + 分析完成标志(1个)
    m_modbusHelper->asyncWrite(REG_CONCENTRATION_LOW, allValues)
        .then([this]() { onStepCompleted(); })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step10_ReadRecoveryRate()
{
    logMessage("步骤10: 读取加标回收率 (0305H-0306H)");

    m_modbusHelper->asyncReadFloat(REG_RECOVERY_LOW, 1, MB_ABCD)
        .then([this](const QVector<float>& values) {
            if (!values.isEmpty()) {
                m_recoveryRate = values[0];
                m_recoveryRateLabel->setText(QString("%1%").arg(m_recoveryRate, 0, 'f', 2));
                logMessage(QString("加标回收率读取成功: %1%").arg(m_recoveryRate, 0, 'f', 2));
                onStepCompleted();
            } else {
                onStepFailed("读取回收率数据为空");
            }
        })
        .fail([this](const QString& error) { onStepFailed(error); });
}

void SpikeRecoveryTestDemo::step11_TestComplete()
{
    logMessage("步骤11: 测试完成");
    logMessage(QString("最终结果 - 第一次浓度: %1, 第二次浓度: %2, 加标回收率: %3")
                   .arg(m_concentration1, 0, 'f', 2)
                   .arg(m_concentration2, 0, 'f', 2)
                   .arg(m_recoveryRate, 0, 'f', 2));

    onStepCompleted();

    QMessageBox::information(this, "测试完成",
                             QString("加标回收测试已完成！\n\n"
                                     "第一次浓度: %1\n"
                                     "第二次浓度: %2\n"
                                     "加标回收率: %3")
                                 .arg(m_concentration1, 0, 'f', 2)
                                 .arg(m_concentration2, 0, 'f', 2)
                                 .arg(m_recoveryRate, 0, 'f', 2));
}

void SpikeRecoveryTestDemo::pollReadyStatus()
{
    m_modbusHelper->asyncRead(REG_READY_STATUS, 1)
        .then([this](const QVector<quint16>& values) {
            if (!values.isEmpty() && values[0] == 1) {
                // 准备完成
                m_pollTimer->stop();
                logMessage("设备准备完成");
                onStepCompleted();
            }
            // 如果未准备完成，继续轮询
        })
        .fail([this](const QString& error) {
            m_pollTimer->stop();
            onStepFailed(error);
        });
}

void SpikeRecoveryTestDemo::logMessage(const QString& message)
{
    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);

    m_logTextEdit->append(logEntry);
    m_logTextEdit->ensureCursorVisible();

    // 同时输出到控制台
    qDebug() << logEntry;
}

void SpikeRecoveryTestDemo::setStepStatus(int stepIndex, const QString& status)
{
    if (stepIndex >= 0 && stepIndex < m_stepLabels.size()) {
        QString styleSheet;
        if (status == "running") {
            styleSheet =
                "QLabel { border: 2px solid blue; padding: 5px; margin: 2px; background-color: "
                "lightblue; }";
        } else if (status == "completed") {
            styleSheet =
                "QLabel { border: 2px solid green; padding: 5px; margin: 2px; background-color: "
                "lightgreen; }";
        } else if (status == "failed") {
            styleSheet =
                "QLabel { border: 2px solid red; padding: 5px; margin: 2px; background-color: "
                "pink; }";
        } else {
            styleSheet = "QLabel { border: 1px solid gray; padding: 5px; margin: 2px; }";
        }

        m_stepLabels[stepIndex]->setStyleSheet(styleSheet);
    }
}